package sf.r2dbc.sql;

import io.r2dbc.spi.Connection;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import sf.common.wrapper.Page;
import sf.core.DBCascadeField;
import sf.core.DBObject;
import sf.database.dialect.DBDialect;
import sf.database.jdbc.sql.PageStrategy;
import sf.database.jdbc.sql.SQLContext;
import sf.database.meta.TableMapping;
import sf.database.support.DMLType;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public interface R2dbcCrudModelInf {
    <T extends DBObject> Mono<Long> selectCount(Connection connection, T query);

    <T extends DBObject> Mono<Boolean> existsByPrimaryKeys(Connection conn, Class<T> clz, Object... keyParams);

    <T extends DBObject> Mono<Boolean> exists(Connection connection, T query);

    <T extends DBObject> Flux<T> selectList(Connection connection, T query);

    <T extends DBObject> Flux<T> selectList(Connection conn, T query, long start, int limit);

    <T extends DBObject> Flux<T> selectListForUpdate(Connection conn, T query);

    <T extends DBObject> Mono<T> selectByPrimaryKeys(Connection connection, Class<T> clz, Object... keyParams);

    Flux<Map<String, Object>> selectListMap(Connection conn, SQLContext context);

    <T extends DBObject> Mono<T> selectOne(Connection connection, T query);

    <T> Mono<T> selectOne(Connection connection, Class<T> beanClass, SQLContext context);

    <T extends DBObject> Mono<T> selectOneForUpdate(Connection connection, T query);

    <T> Flux<T> selectList(Connection conn, Class<T> beanClass, SQLContext context);

    <T> Flux<T> selectList(Connection conn, Class<T> beanClass, SQLContext context, long start, int limit);

    <T extends DBObject> Mono<Integer> update(Connection connection, T entity);

    <T extends DBObject> Mono<Integer> updateAndSet(Connection connection, T obj);

    /**
     * @param conn
     * @param obj
     * @param <T>
     * @return
     */
    <T extends DBObject> Mono<Integer> updateWithVersion(Connection conn, T obj);

    Mono<Integer> merge(Connection connection, DBObject obj);

    <T extends DBObject> Mono<Integer> deleteByPrimaryKeys(Connection conn, Class<T> clz, Object... keyParams);

    <T extends DBObject> Mono<Integer> delete(Connection connection, T entity);

    Flux<Integer> batchInsert(Connection conn, Collection<? extends DBObject> modelList, boolean insertFast, boolean useOptimisticLock);

    Flux<Integer> batchUpdate(Connection conn, Collection<? extends DBObject> modelList);

    Flux<Integer> batchDelete(Connection conn, Collection<? extends DBObject> modelList);

    Flux<Integer> batch(Connection connection, DBDialect dialect, TableMapping table, String sql, List<SQLContext> list, List<Integer> dataSizeList, List<DBObject> dataList, DMLType type, boolean insertFast);

    /**
     * fixme beetsql hibernate 使用了一级缓存,导致比他们慢
     * 根据查询条件查询列表并根据级联字段查询级联对象
     * @param conn
     * @param query
     * @param clz
     * @param fields
     * @param <T>
     * @return 返回结果
     */
    <T extends DBObject> Flux<T> fetchCascade(Connection conn, T query, Class<T> clz, DBCascadeField... fields);

    /**
     * 根据一个正则表达式，获取对象所有的关联字段
     * @param conn
     * @param obj  数据对象,不可以是Class啊!!!传对象或集合啊!!!
     * @param <T>
     * @return 更新后的数据对象本身
     * @see javax.persistence.OneToOne
     * @see javax.persistence.ManyToMany
     * @see javax.persistence.OneToMany
     */
    <T extends DBObject> Mono<T> fetchLinks(Connection conn, T obj);

    /**
     * 根据字段，获取对象所有的关联字段
     * @param conn
     * @param obj    数据对象,不可以是Class啊!!!传对象或集合啊!!!
     * @param fields
     * @param <T>
     * @return 更新后的数据对象本身
     * @see javax.persistence.OneToOne
     * @see javax.persistence.ManyToMany
     * @see javax.persistence.OneToMany
     */
    <T extends DBObject> Mono<T> fetchLinks(Connection conn, T obj, DBCascadeField... fields);

    /**
     * 根据字段，获取对象所有的关联字段
     * @param conn   连接对象
     * @param obj    数据对象,不可以是Class啊!!!传对象或集合啊!!!
     * @param fields 枚举字符串
     * @param <T>
     * @return 更新后的数据对象本身
     * @see javax.persistence.OneToOne
     * @see javax.persistence.ManyToMany
     * @see javax.persistence.OneToMany
     */
    <T extends DBObject> Mono<T> fetchLinks(Connection conn, T obj, String... fields);

    <T extends DBObject> Mono<Page<T>> selectPage(Connection conn, T query, long start, int limit);

    <T> Mono<Page<T>> selectPage(Connection conn, long start, int limit, Class<T> beanClass, SQLContext context);

    <T> Mono<Page<T>> selectPage(Connection conn, long start, int limit, Class<T> beanClass, SQLContext context, PageStrategy strategy);

    /**
     * 插入
     * @param connection
     * @param obj
     * @param <T>
     * @return 记录变更数量
     */
    <T extends DBObject> Mono<Integer> insert(Connection connection, T obj);

    /**
     * @param connection
     * @param obj
     * @param fast              是否是快速插入
     * @param useOptimisticLock
     * @param <T>
     * @return 记录变更数量
     */
    <T extends DBObject> Mono<Integer> insert(Connection connection, T obj, boolean fast, boolean useOptimisticLock);

    /**
     * 将对象插入数据库同时，也将符合一个正则表达式的所有关联字段关联的对象统统插入相应的数据库
     * <p>
     * 关于关联字段更多信息，请参看 '@One' | '@Many' | '@ManyMany' 更多的描述
     * @param conn
     * @param obj
     * @param fields 指定字段,控制力度更细,至少一个或多个 描述了什么样的关联字段将被关注。如果为 null，则表示全部的关联字段都会被插入
     * @return 记录变更数量
     */
    Mono<Integer> insertCascade(Connection conn, DBObject obj, DBCascadeField... fields);

    /**
     * 仅将对象所有的关联字段插入到数据库中，并不包括对象本身
     * @param obj    数据对象
     * @param fields 字段名称，描述了什么样的关联字段将被关注。如果为 null，则表示全部的关联字段都会被插入
     * @return 数据对象本身
     * @see javax.persistence.OneToOne
     * @see javax.persistence.ManyToMany
     * @see javax.persistence.OneToMany
     */
    <T extends DBObject> Mono<T> insertLinks(Connection con, T obj, DBCascadeField... fields);

    /**
     * 将对象的一个或者多个，多对多的关联信息，插入数据表
     * @param obj    对象
     * @param fields 正则表达式，描述了那种多对多关联字段将被执行该操作
     * @return 对象自身
     * @see javax.persistence.ManyToMany
     */
    <T extends DBObject> Mono<T> insertRelation(Connection con, T obj, DBCascadeField... fields);

    /**
     * 将对象更新的同时，也将符合一个正则表达式的所有关联字段关联的对象统统更新
     * <p>
     * 关于关联字段更多信息，请参看 '@One' | '@Many' | '@ManyMany' 更多的描述
     * @param conn
     * @param obj    数据对象
     * @param fields 指定字段,控制力度更细,至少一个或多个,描述了什么样的关联字段将被关注。如果为 null，则表示全部的关联字段都会被更新
     * @return 记录变更数量
     */
    Mono<Integer> updateCascade(Connection conn, DBObject obj, DBCascadeField... fields);

    /**
     * 仅更新对象所有的关联字段，并不包括对象本身
     * @param con    连接
     * @param obj    数据对象
     * @param fields 字段名称，描述了什么样的关联字段将被关注。如果为 null，则表示全部的关联字段都会被更新
     * @param <T>
     * @return 对象内部更新的级联数量
     * @see javax.persistence.OneToOne
     * @see javax.persistence.ManyToMany
     * @see javax.persistence.OneToMany
     */
    <T extends DBObject> Mono<Integer> updateLinks(Connection con, T obj, DBCascadeField... fields);

    /**
     * 多对多关联是通过一个中间表将两条数据表记录关联起来。
     * <p>
     * 而这个中间表可能还有其他的字段，比如描述关联的权重等
     * <p>
     * 这个操作可以让你一次更新某一个对象中多个多对多关联的数据
     * @param con    数据库连接
     * @param obj    数据对象
     * @param fields 字段名称，描述了那种多对多关联字段将被执行该操作
     * @return 共有多少条数据被更新
     * @see javax.persistence.ManyToMany
     */
    <T extends DBObject> Mono<Integer> updateRelation(Connection con, T obj, DBCascadeField... fields);


    /**
     * @param conn
     * @param clz
     * @param keyParams
     * @param <T>
     * @return
     */
    <T extends DBObject> Mono<Integer> logicDeleteByPrimaryKeys(Connection conn, Class<T> clz, Object... keyParams);

    /**
     * @param conn
     * @param logicDelete
     * @param clz
     * @param keyParams
     * @param <T>
     * @return
     */
    <T extends DBObject> Mono<Integer> deleteByPrimaryKeys(Connection conn, boolean logicDelete, Class<T> clz, Object... keyParams);

    /**
     * @param conn
     * @param obj
     * @return
     */
    Mono<Integer> logicDelete(Connection conn, DBObject obj);

    /**
     * @param conn
     * @param logicDelete
     * @param obj
     * @return
     */
    Mono<Integer> delete(Connection conn, boolean logicDelete, DBObject obj);

    /**
     * 执行语句,非查询语句
     * @param conn
     * @param context
     * @return 记录变更数量
     */
    Mono<Integer> execute(Connection conn, SQLContext context);

    /**
     * 将对象删除的同时，也将符合一个正则表达式的所有关联字段关联的对象统统删除
     *
     * <b style=color:red>注意：</b>
     * <p>
     * Java 对象的字段会被保留，这里的删除，将只会删除数据库中的记录
     * <p>
     * 关于关联字段更多信息，请参看 '@One' | '@Many' | '@ManyMany' 更多的描述
     * @param conn
     * @param obj
     * @param fields 指定字段,控制力度更细,至少一个或多个 描述了什么样的关联字段将被关注。如果为 null，则表示全部的关联字段都会被删除
     * @param <T>
     * @return 记录变更数量
     */
    <T extends DBObject> Mono<Integer> deleteCascade(Connection conn, T obj, DBCascadeField... fields);

    /**
     * 仅删除对象所有的关联字段，并不包括对象本身。
     *
     * <b style=color:red>注意：</b>
     * <p>
     * Java 对象的字段会被保留，这里的删除，将只会删除数据库中的记录
     * <p>
     * 关于关联字段更多信息，请参看 '@One' | '@Many' | '@ManyMany' 更多的描述
     * @param obj    数据对象
     * @param fields 字段名称，描述了什么样的关联字段将被关注。如果为 null，则表示全部的关联字段都会被删除
     * @return 被影响的记录行数
     * @see javax.persistence.OneToOne
     * @see javax.persistence.ManyToOne
     * @see javax.persistence.ManyToMany
     */
    <T extends DBObject> Mono<Integer> deleteLinks(Connection con, T obj, DBCascadeField... fields);

    /**
     * 多对多关联是通过一个中间表将两条数据表记录关联起来。
     * <p>
     * 而这个中间表可能还有其他的字段，比如描述关联的权重等
     * <p>
     * 这个操作可以让你一次删除某一个对象中多个多对多关联的数据
     * @param obj
     * @param fields 字段名称，描述了那种多对多关联字段将被执行该操作
     * @return 共有多少条数据被更新
     * @see javax.persistence.ManyToMany
     */
    <T extends DBObject> Mono<Integer> deleteRelation(Connection con, T obj, DBCascadeField... fields);
}
